package twoD.IsoPfem.EmbededCrackModels;

import inf.jlinalg.IMatrix;
import inf.jlinalg.IVector;
import inf.jlinalg.MatrixFormat;

import java.util.ArrayList;

import twoD.IsoPfem.Mesh;
import twoD.IsoPfem.RealTable;
import twoD.IsoPfem.Structure;

public class CrackStructure extends Structure {

	protected ArrayList<IEmbeddedCrackElement> elements_;

	private ICrackInitiationCondition cIC_;
	private LoadingFunction lF_;
	private RealTable realTable_;

	public CrackStructure(Mesh M) {
		super(M);
		elements_ = new ArrayList<IEmbeddedCrackElement>();
	}

	public void setCrackInitiationCondition(ICrackInitiationCondition cic) {
		cIC_ = cic;
	}

	public void setLoadingFunction(LoadingFunction lf) {
		lF_ = lf;
	}

	public IEmbeddedCrackElement addElement(IEmbeddedCrackElement e) {
		elements_.add(e);
		return e;
	}

	@Override
	public IEmbeddedCrackElement getElements(int i) {
		return elements_.get(i);
	}

	public int getNumberOfElements() {
		return elements_.size();
	}

	public void setRealTable(RealTable rt) {
		realTable_ = rt;
	}

	public void assembleTangentStiffnessMatrix(CrackingState st, IMatrix kGlobal,
			boolean full) {
		for (int i = 0; i < getNumberOfElements(); i++) {
			IMatrix ke;
			if (!getElements(i).isCrack())
				ke = getElements(i).computeTangentStiffnessMatrix();
			else {
				// ke = elements_.get(i).computeStiffnessMatrix(
				// realTable_.getDhat2D(), st.getGamma(i));
				ke = getElements(i).computeStiffnessMatrix(lF_,
						realTable_.getDhat2D(), st.getGamma(i),
						st.getCrackOpeningParameters(i),
						getElements(i).isFirstTimeCrack());
				// System.out.println("ke" + i + "=" + MatrixFormat.format(ke));
			}
			int[] dofNumbers = elements_.get(i).getDOFNumbers()[0];
			for (int p = 0; p < 6; p++)
				for (int q = full ? 0 : p; q < 6; q++)
					if (dofNumbers[p] != -1 && dofNumbers[q] != -1)
						kGlobal.add(dofNumbers[p], dofNumbers[q], ke.get(p, q));
		}
	}

	/**
	 * 
	 * @return the maximum max-principal stress in the structure
	 */
	public double checkCrackInitiationCondition() {
		double sigmamax = 0.0;
		for (int i = 0; i < getNumberOfElements(); i++) {
			double[] sigma1 = elements_.get(i).computeSigma1();
			if (cIC_.check(sigma1[0]))
				if (!getElements(i).isCrack()) {
					getElements(i).setCrack(true);
					getElements(i).setCrackSlope(
							Math.atan2(sigma1[2], sigma1[1]));
					getElements(i).setFirstTimeCrack(true);
					getElements(i).fixCrack();
					// fix the crack (i.e fix the matrix A and H for the
					// element)
				}
			if (sigma1[0] > sigmamax)
				sigmamax = sigma1[0];
		}
		return sigmamax;
	}

	public void updateCrackingState(double[] gamma, IVector[] e) {
		IMatrix Dhat = realTable_.getDhat2D();
		for (int i = 0; i < getNumberOfElements(); i++) {
			if (getElements(i).isCrack()) {
				System.out.println("Cracked element " + i + ":");
				System.out.println("initial gamma of element " + i + " ="
						+ gamma[i]);
				System.out.println("intitial e of element " + i
						+ MatrixFormat.format(e[i]));
				gamma[i] = getElements(i).updateCrackingState(lF_, Dhat,
						gamma[i], e[i], getElements(i).isFirstTimeCrack());

				if (getElements(i).isFirstTimeCrack())
					getElements(i).setFirstTimeCrack(false);
				// after this command, crackStart_[i] will never be turned
				// on again, element has passed through initial cracking
				// state
				System.out.println("converged compliance parameter = "
						+ gamma[i]);
				System.out.println("converged crack opening parameters: "
						+ MatrixFormat.format(e[i]));
			}
		}
	}

	@Override
	public void updateInternalState() {
		// checking crack initiation condition
		double sigmamax = checkCrackInitiationCondition();
		System.out.println("Maximum stress = " + sigmamax);

		// compute crack opening parameters and compliance parameter for
		// cracked element
		// double[] gamma = state_.get(it).getGamma().clone();
		// IVector[] e = state_.get(it).getCrackOpeningParameters().clone();
		// updateCrackingState(gamma, e);
	}

}
